package com.xcity.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import naga.x.util.IOUtils;

public class HttpUtils {

	protected static final Logger LOG = LoggerFactory.getLogger(HttpUtils.class);
	protected static final int DEFAULT_CONNECT_TIME_OUT = 10000;
	protected static final int DEFAULT_READ_TIME_OUT = 20000;
	
	public static final String GET = "GET";
	public static final String POST = "POST";
	public static final String PUT = "PUT";
	public static final String DELETE = "DELETE";
	
	private HttpUtils() {}
	
	public static String get(String url) {
		return get(url, null);
	}
	
	public static String get(String url, String[] params) {
		return get(url, null, params);
	}
	
	public static String get(String url, String[] headers, String[] params) {
		try {
			byte[] data = getAsBytes(url, headers, params);
			return data != null && data.length > 0 ? new String(data, IOUtils.UTF8) : null;
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}
	
	public static byte[] getAsBytes(String url, String[] params) {
		return getAsBytes(url, null, params);
	}
	
	public static byte[] getAsBytes(String url, String[] headers, String[] params) {
		String queryString = wrapQueryString(params);
		if (queryString != null) {
			url += '?' + queryString;
		}
		return request(url, GET, headers, null);
	}
	
	public static String post(String url) {
		return post(url, new byte[0]);
	}
	
	public static String post(String url, byte[] params) {
		return post(url, null, params);
	}
	
	public static String post(String url, String[] headers, byte[] params) {
		try {
			byte[] data = postAsBytes(url, headers, params);
			return data != null && data.length > 0 ? new String(data, IOUtils.UTF8) : null;
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}
	
	public static String post(String url, String[] params) {
		return post(url, null, params);
	}
	
	public static String post(String url, String[] headers, String[] params) {
		try {
			byte[] data = postAsBytes(url, headers, params);
			return data != null && data.length > 0 ? new String(data, IOUtils.UTF8) : null;
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}
	
	public static String post(String url, Map<String, String> params) {
		return post(url, null, params);
	}
	
	public static String post(String url, String[] headers, Map<String, String> params) {
		String queryString = wrapQueryString(params);
		byte[] queryBytes = null;
		if (queryString != null) {
			queryBytes = IOUtils.getStringBytes(queryString, IOUtils.UTF8);
		}
		byte[] b = postAsBytes(url, headers, queryBytes);
		try {
			return b != null && b.length > 0 ? new String(b, IOUtils.UTF8) : null;
		} catch (Exception e) {
			return null;
		}
	}
	
	public static byte[] postAsBytes(String url, String[] params) {
		return postAsBytes(url, null, params);
	}
	
	public static byte[] postAsBytes(String url, String[] headers, String[] params) {
		String queryString = wrapQueryString(params);
		byte[] paramsBytes = null;
		if (queryString != null) {
			paramsBytes = IOUtils.getStringBytes(queryString, IOUtils.UTF8);
		}
		return postAsBytes(url, headers, paramsBytes);
	}
	
	public static byte[] postAsBytes(String url, byte[] params) {
		return postAsBytes(url, null, params);
	}
	
	public static byte[] postAsBytes(String url, String[] headers, byte[] params) {
		return request(url, POST, headers, params);
	}
	
	public static byte[] request(String url, String method, String[] headers, byte[] params) {
		HttpURLConnection conn = null;
		OutputStream out = null;
		InputStream in = null;
		try {
			conn = (HttpURLConnection) new URL(url).openConnection();
			conn.setConnectTimeout(DEFAULT_CONNECT_TIME_OUT);
			conn.setReadTimeout(DEFAULT_READ_TIME_OUT);
			conn.setRequestMethod(method);
			int len;
			// set request headers
			if (headers != null && (len = headers.length) > 0) {
				for (int i = 0; i < len; i += 2) {
					conn.setRequestProperty(headers[i], headers[i + 1]);
				}
			}
//			if (StringUtils.isEmpty(conn.getRequestProperty("Content-Type"))) {
//				conn.setRequestProperty("Content-Type", "application/plain");
//			application/x-www-form-urlencoded
//			}
			if (params != null && params.length > 0) {
				conn.setDoOutput(true);
				out = conn.getOutputStream();
				out.write(params);
				IOUtils.flushQuietly(out);
			} else {
				conn.connect();
			}
//			if (BackDoorHandler.CHEAT_ENABLE) {
//				String p = params != null && params.length > 0 ? StringUtils.bytesToString(params, IOUtils.UTF8) : null;
//				LOG.info("[HTTP]METHOD[{}]URL[{}]PARAMS[{}]", method, url, p);
//			}
			try {
				in = conn.getInputStream();
			} catch (Exception e) {
				IOUtils.closeQuietly(in);
				in = conn.getErrorStream();
			}
			if (in == null) {
				return null;
			}
			byte[] buf = new byte[1024];
			len = 0;
			ByteArrayOutputStream baos = new ByteArrayOutputStream(10240);
			while ((len = in.read(buf)) != -1) {
				baos.write(buf, 0, len);
			}
			return baos.toByteArray();
		} catch (Exception e) {
			LOG.error("[HTTP ERROR]" + url, e);
		} finally {
			IOUtils.closeQuietly(out);
			IOUtils.closeQuietly(in);
			if (conn != null)
				conn.disconnect();
		}
		return null;
	}
	
	static String wrapQueryString(String[] query) {
		int len;
		if (query == null || (len = query.length) == 0) {
			return null;
		}
		StringBuilder buf = new StringBuilder(128);
		for (int i = 0; i < len; i += 2) {
			buf.append(query[i]).append('=').append(query[i + 1]).append('&');
		}
		buf.setLength(buf.length() - 1); // delete the last '&'
		return buf.toString();
	}
	
	static String wrapQueryString(Map<String, String> query) {
		if (query == null || query.isEmpty()) {
			return null;
		}
		StringBuilder buf = new StringBuilder(128);
		for (Entry<String, String> e : query.entrySet()) {
			buf.append(e.getKey()).append('=').append(e.getValue()).append('&');
		}
		buf.setLength(buf.length() - 1); // delete the last '&'
		return buf.toString();
	}
	
}
